//
//  NetworkListener.m
//  EClub
//
//  Created by iBenz on 16/6/3.
//  Copyright © 2016年 EC. All rights reserved.
//

#import "NetworkListener.h"
#import "GCDMulticastDelegate.h"
#import "Reachability.h"

NSString *const kNetworkListenerChangedNotification = @"kNetworkListenerChangedNotification";

@interface NetworkListener ()
@property(nonatomic, strong) GCDMulticastDelegate<NetworkListenerDelegate> *multiDelegate;
@property(nonatomic, strong) Reachability *reachability;
@end

@implementation NetworkListener

+ (instancetype)shareListener {
    static NetworkListener *listener = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        listener = [[NetworkListener alloc] init];
    });
    return listener;
}

- (void)dealloc {
    [_multiDelegate removeAllDelegates];
    [_reachability stopNotifier];
    _reachability.reachableBlock = nil;
    _reachability.unreachableBlock = nil;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        [self reachabilityDidChanged:self.reachability];
        [self.reachability startNotifier];
    }
    return self;
}

#pragma mark - Public

- (void)addDelegate:(id<NetworkListenerDelegate>)delegate delegateQueue:(dispatch_queue_t)aQueue {
    [self.multiDelegate addDelegate:delegate delegateQueue:aQueue?aQueue:dispatch_get_main_queue()];
}

- (void)removeDelegate:(id<NetworkListenerDelegate>)delegate delegateQueue:(dispatch_queue_t)aQueue {
    [_multiDelegate removeDelegate:delegate delegateQueue:aQueue?aQueue:dispatch_get_main_queue()];
}

- (void)removeDelegate:(id<NetworkListenerDelegate>)delegate {
    [_multiDelegate removeDelegate:delegate];
}

- (void)removeAllDelegates {
    [_multiDelegate removeAllDelegates];
}

#pragma mark - Private

- (GCDMulticastDelegate<NetworkListenerDelegate> *)multiDelegate {
    if (!_multiDelegate) {
        _multiDelegate = (GCDMulticastDelegate <NetworkListenerDelegate> *)GCDMulticastDelegate.new;
    }
    return _multiDelegate;
}

- (Reachability *)reachability {
    if (!_reachability) {
        //不使用通知方式监听网络状态变化，因为其他人也有可能使用Reachability直接初始化对象，会出现多次接收通知事件
        //bility = [Reachability reachabilityWithHostName:@"www.baidu.com"];
        Reachability *bility = [Reachability reachabilityForInternetConnection];
        __weak typeof(self) weak = self;
        bility.reachableBlock = ^(Reachability *objc) {
            [weak reachabilityDidChanged:objc];
        };
        bility.unreachableBlock = ^(Reachability *objc) {
            [weak reachabilityDidChanged:objc];
        };
        _reachability = bility;
    }
    return _reachability;
}

- (void)reachabilityDidChanged:(Reachability *)obj {
    NetworkStatus status = obj.currentReachabilityStatus;
    switch (status) {
        case ReachableViaWWAN:
            self.currentStatus = NetStatusCellular;
            break;
        case ReachableViaWiFi:
            self.currentStatus = NetStatusWiFi;
            break;
        default:
            self.currentStatus = NetStatusNone;
            break;
    }
}

- (void)setCurrentStatus:(NetStatus)currentStatus {
    _currentStatus = currentStatus;
    GCDMulticastDelegateEnumerator *enumer = _multiDelegate.delegateEnumerator;
    for (NSInteger idx=0; idx<enumer.count; idx++) {
        id<NetworkListenerDelegate> del = nil;
        dispatch_queue_t _queue = NULL;
        if ([enumer getNextDelegate:&del delegateQueue:&_queue]) {
            dispatch_async(_queue, ^{
                if ([del respondsToSelector:@selector(networkListener:didChangedToNetworkStatus:)]) {
                    [del networkListener:self didChangedToNetworkStatus:currentStatus];
                }
            });
        };
    }
}

@end
